Internal · Living Document

Dunwell
Design Standard

The shared UI layer — what every brand must implement to feel like a Dunwell company. Personality, recognition, and craft, codified.

June 2026
v1.0
5 brands covered
D.
01 — The Fingerprint

Eight things that make a Dunwell brand

A customer who uses Aptly, then discovers Tacet, should feel something familiar before they can name it. These eight elements are the connective tissue — each one is either required or strongly recommended across all brands.

01 · Required
.
The Period
Every brand name ends with a period in the logo. Aptly. Tacet. Graft. Lucro. Invio. The dot is deliberate — not punctuation, a mark of completion.
02 · Required
Aa
The Type Stack
Newsreader (serif) + Hanken Grotesk (sans) + JetBrains Mono. All three. Any page with all three in play feels Dunwell — even before a logo is visible.
03 · Required
The Sheen
A diagonal light sweep on every primary button hover. Same animation, same easing across all brands. Subtle — just enough to feel crafted.
04 · Required
Dark + Light
Every site ships with both dark and light themes. Dark is default on most brands. The toggle is always reachable in the nav. State persists in localStorage.
05 · Required
Seasonal Accent
The brand accent color shifts with the calendar via dunwell-seasons.js. 26 events auto-detected. Each brand has its own color map. One shared engine.
06 · Required
D.
Dunwell Footer
"a Dunwell company" appears in small mono text in every brand footer, linking to dunwell.group. The quiet credential that compounds over time.
07 · Required
Easter Egg
At least one hidden interaction per brand. Rewards the curious. Signals that a human made this. Becomes a shared reputation across the portfolio.
08 · Recommended
Mono Labels
JetBrains Mono for all UI chrome — nav items, section eyebrows, badges, metadata. Uppercase, wide tracking (0.14–0.22em), 9–11px. The technical voice.
01.5 — The Mark

Rules, not style.

Every Dunwell brand has a wordmark. What that wordmark looks like is entirely up to the brand — typeface, weight, color, style. What it must contain is non-negotiable. The system standardizes the rules. The brand owns the expression. Invio being brutalist yellow is not a deviation — it's the point. Each brand was built for a different audience, and the mark should reflect that.

Required — every brand
Brand name is the mark — no separate icon required
Period ends the wordmark, always in brand accent color
Legible at 20px (nav) and 200px (hero/OG image)
Dark and light versions — both must work
Works in a single color (no gradient dependence)
Free — brand's choice
Typeface — serif, sans, display, mono, anything
Visual style — editorial, brutalist, cinematic, clean
Weight and letterform — light, heavy, mixed
Additional mark or icon — optional, brand's call
Tagline placement — under, beside, or omitted
Current wordmarks
Aptly.
Aptly · editorial
Tacet.
Tacet · cinematic
Graft.
Graft · forge
Lucro.
Lucro · growth
INVIO.
Invio · brutalist
Five completely different styles. One rule in common: the period. That's the system.
02 — Typography

The shared type stack

Three typefaces. Every brand uses all three. The combination is the signature — editorial serif for brand moments, clean sans for UI, mono for metadata and code. Never substitute.

Newsreader Serif · Roman + Italic
Google Fonts · Optical sizing
Weights: 300–600
Use: Headlines, wordmarks,
brand statements, pull quotes
Roman
Building structure that holds.
The pause before you go live.
Résumé, rebuilt from the ground up.
Small business deserves serious digital.
Italic
Stay current.
Craft that compounds over time.
Hanken Grotesk Sans-serif · UI default
Google Fonts
Weights: 300–700
Use: Body copy, UI labels,
cards, buttons (alt)
Photography, videography,
and live production.
JetBrains Mono Monospace · Chrome voice
Google Fonts
Weights: 400–600
Use: Nav, eyebrows, badges,
buttons, metadata, code
Services · Work · Pricing · Contact
tryaptly.app · getgraft.ca
getlucro.ca · tacet.ca · tryinvio.ca
/* Required Google Fonts import — all brands */
@import url('https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300..600;1,6..72,300..600&family=Hanken+Grotesk:wght@300..700&family=JetBrains+Mono:wght@400;500;600&display=swap');

/* Required CSS variables */
:root {
  --serif: 'Newsreader', Georgia, serif;
  --sans:  'Hanken Grotesk', system-ui, sans-serif;
  --mono:  'JetBrains Mono', monospace;
}
03 — Color

Brand accents + seasonal layer

Each brand owns one accent color. That accent becomes --accent in their CSS. The seasonal engine then overrides it with --season-accent for contextual personality. Making --accent: var(--season-accent, [default]) wires both at once.

Aptly.
Aptly
#b23a2e
Ember red. The editorial red pen.
Tacet
#c9a94a
Amber gold. Cinematic, deliberate.
Graft
#9E6B38
Cognac brown. Craft, roots, forge.
Lucro
#1A7A60
Emerald teal. Growth, clarity.
Invio
#1F5BA0
Steel blue. Precision, B2B.
Seasonal accent — current auto-detection · today is
04 — Buttons

The sheen is the signature

Every primary and ghost button carries two effects: a monochromatic gradient (subtle tonal depth, always baked in) and the sheen animation (diagonal light sweep on hover). Same keyframe, same easing across every brand. The gradient changes with the accent color automatically — no extra work.

Live demo — hover to see sheen + gradient together
Monochromatic gradient
A subtle top-to-bottom or diagonal tonal shift using the brand's accent color. Lighter at the top, slightly deeper at the bottom. Gives the button a sense of depth. Never a two-color gradient — always the same hue, slightly varied in lightness.
CSS — copy for every brand
.btn-primary {
  background: linear-gradient(
    160deg,
    color-mix(in srgb, var(--accent) 85%, white),
    var(--accent) 50%,
    color-mix(in srgb, var(--accent) 85%, black)
  );
}
/* ── Shared sheen animation — paste into every brand ── */
@keyframes dw-shine { to { left: 120% } }

/* Primary */
.btn-primary {
  font-family: var(--mono); font-size: 10px; font-weight: 500;
  letter-spacing: .15em; text-transform: uppercase;
  background: var(--accent); color: var(--bg);
  padding: 13px 28px; border: none; cursor: pointer;
  position: relative; overflow: hidden;
}
.btn-primary::after {
  content: ""; position: absolute;
  top: 0; bottom: 0; left: -65%; width: 40%;
  background: linear-gradient(105deg, transparent, rgba(255,255,255,.3), transparent);
  transform: skewX(-18deg); pointer-events: none;
}
.btn-primary:hover::after { animation: dw-shine .65s ease-out; }
.btn-primary:hover { opacity: .88; }
Shape consistency rule: Each brand picks one border-radius and applies it to every interactive button on that site. Not per-page, not per-section — everywhere. Buttons evolve inconsistently when shape isn't locked early. Lock it at the start.
Sharp — border-radius: 0
Suits: Invio, Graft. Brutalist, forge, B2B, precision.
Soft — border-radius: 4–6px
Suits: Aptly, Lucro. Editorial, approachable, consumer SaaS.
Pill — border-radius: 999px
Suits: badges, tags, season pills. Not for primary CTAs.
✓ Do
Pick one radius at brand start · use it for every button
Icon-only circular buttons are a separate class — fine to round
Tags and badges can be pill-shaped — they're not action buttons
✗ Don't
Mix sharp and rounded CTAs on the same page
Let button shape evolve section by section
Use pill shape for primary CTAs — reserve pills for labels
07 — Seasonal Engine

26 events. One file. Every brand.

The engine lives at shared/dunwell-seasons.js. Load it before your brand script. Each brand passes its own accent color map — the natural season color filtered through the brand's palette. Append ?season=christmas to any URL to test any event instantly.

Current session — detecting…
<!-- 1. Load engine in <head> -->
<script src="../shared/dunwell-seasons.js"></script>

<!-- 2. Init immediately after -->
<script>
  DunwellSeasons.init({
    accentMap:   DunwellSeasons.BRAND_MAPS.graft,  // aptly | tacet | graft | lucro | invio
    themeKey:    'graft_theme',
    darkDefault: true,
  });
</script>

/* 3. In CSS — wire accent to season */
:root { --accent: var(--season-accent, #9E6B38); }
08 — Animation Vocabulary

Same rhythm, every brand

Consistent easing and timing makes brands feel related even when they look different. These values are the Dunwell timing standard — copy them verbatim.

Button sheen
.65s ease-out
Primary + ghost buttons. Fires once on hover-enter. The diagonal sweep from left:-65% to left:120%.
Theme transition
.25s ease
Applied to body: background, color, border-color. Smooth crossfade between dark and light. No layout shift.
Nav scroll
.3s ease, .25s ease
Background fade-in .3s, padding collapse .25s. Triggered when scrollY > 60px.
Section entrance
.5s cubic-bezier(.2,1,.4,1)
Elements rise 12px + fade in. Used for hero content, card grids, section headers on scroll-enter.
Card hover lift
translateY(-3px) .15s ease
Subtle float on interactive cards. Never more than 4px. Paired with soft shadow increase.
Logo animation
.5s cubic-bezier(.2,1.4,.4,1)
The overshoot spring easing for animated logo intros. The "." drops with dropBounce, text lifts with liftIn.
09 — Easter Eggs

Every brand hides something

Required: at least one hidden interaction per brand. They reward curiosity, signal craft, and build a shared Dunwell reputation. The trigger should be brand-appropriate — not random. The payoff should feel earned.

Aptly. · the red pen
Trigger: Click the wordmark 5× fast
The resume score animates to A+ with a red pen scribble annotation. Resets after 3s. On-brand: the editor's highest grade.
Tacet · deliberate silence
Trigger: Click the nav logo 5× fast
All dust particles freeze. The spotlight dims to black. After 2s of silence — everything resumes. Tacet: the pause before you go live.
Graft · roots
Trigger: Konami code (↑↑↓↓←→←→BA)
The roots canvas animation goes full-screen for 3s with a "Built with Graft." stamp. Forge energy — found by those who look.
Lucro · growth
Trigger: Hold Alt + click any chart
All values multiply by 10x for 2s with a "🚀 10x mode" badge. Aspirational — every founder's dream briefly visualized.
Invio · precision
Trigger: Type "debug" anywhere on the page
A terminal-style overlay shows a fake "inventory audit complete — 0 discrepancies found." Nods to the B2B precision persona.
The rule
Trigger must be discoverable
by curiosity, not accident.
Payoff must be on-brand.
10 — Brand Completeness Checklist

Before a brand launches

Every item marked Required must be complete before a brand goes live. Recommended items should be planned and scheduled. This checklist applies to every brand under the Dunwell holding group.

01
Wordmark with period Brand name ends with . in all logo uses
Required
02
Type stack loaded Newsreader + Hanken Grotesk + JetBrains Mono
Required
03
Dark + light themes Both implemented, toggle in nav, state persists
Required
04
Sheen on all primary buttons dw-shine keyframe, .65s ease-out
Required
05
Seasonal accent engine dunwell-seasons.js + brand accent map
Required
06
Season badge in nav Auto-populated, icon + name, gold tint
Required
07
"a Dunwell company" footer Links to dunwell.group, small mono text
Required
08
Easter egg implemented At least one, brand-appropriate trigger + payoff
Required
09
Animated logo 500×500, looping, exportable as GIF for social
Recommended
10
Brand doc complete Colors, type, voice, do/don't, logo grid
Recommended
11
OG image 1200×630 SVG/PNG, brand mark, tagline
Recommended
12
SVG favicon Brand mark, legible at 16px, inline SVG preferred
Recommended
Current portfolio status
DUNWELL
Period ✓
Type stack ✓
Dark/light ✓
Sheen ✓
Seasons ✓
Season badge ✓
Footer ✓
Easter egg ✓
APTLY
Period ✓
Type stack ✓
Dark/light ✓
Sheen ✓
Seasons ✓
Season badge ✓
Footer ✓
Easter egg ✓
TACET
Period ✓
Type stack ✓
Dark/light ✗
Sheen ✗
Seasons ✓
Season badge ✓
Footer ✓
Easter egg ✗
GRAFT
Period ✓
Type stack ✓
Dark/light ✓
Sheen ✗
Seasons ✗
Season badge ✓
Footer ✓
Easter egg ✗
LUCRO
Period ✓
Type stack ✓
Dark/light ✓
Sheen ✗
Seasons ✗
Season badge ✓
Footer ✓
Easter egg ✗
INVIO
Period ✓
Type stack ✓
Dark/light ✓
Sheen ✗
Seasons ✗
Season badge ✓
Footer ✓
Easter egg ✗